package com.rizzo.infrastructure.performance.redis;

import com.rizzo.infrastructure.aop.MethodProceeding;
import com.rizzo.infrastructure.domain.KeyType;
import com.rizzo.infrastructure.performance.PerformanceMonitor;
import com.rizzo.infrastructure.redis.config.RedisConfigManager;
import com.rizzo.infrastructure.redis.key.RedisKey;
import com.rizzo.infrastructure.redis.key.RedisKeyBuilder;
import com.rizzo.infrastructure.redis.timeseries.TimeStep;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.StopWatch;

public class DirectRedisPerformanceMonitor implements PerformanceMonitor {

    private SecurityContextHolderStrategy securityContextHolderStrategy;

    private RedisTemplate<RedisKey, String> performanceRedisTemplate;

    private RedisConfigManager redisConfigManager;

    private String application;

    @Override
    public Object monitorPerformance(String declaringClass, String method, boolean userBound, MethodProceeding methodProceeding) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            return methodProceeding.proceed();
        } finally {
            stopWatch.stop();
            String principal;
            if (userBound && securityContextHolderStrategy != null) {
                principal = securityContextHolderStrategy.getContext().getAuthentication().getName();
            } else {
                principal = RedisKey.ANONYMOUS;
            }
            final long now = DateTime.now().getMillis();
            String timestamp = String.valueOf(now);
            Period performanceTimeStep =
                    TimeStep.parsePeriod(redisConfigManager.getUserConfig(principal, application, "performanceTimeStep"));
            String performanceDurationZeroPaddings =
                    redisConfigManager.getSystemConfig("performanceDurationZeroPaddings");
            RedisKey appendingPerformanceKey = new RedisKeyBuilder().key(application).type(KeyType.PERFORMANCE).category(declaringClass)
                    // TODO fill instance tags from amazon library http://aws.amazon.com/sdkforjava/
                    .instanceIndex("1").instanceName("ec2")
                    .data(principal).data(TimeStep.encodeTimeStep(new DateTime(now), performanceTimeStep)).build();
            String durationPadded =
                    String.format("%0" + performanceDurationZeroPaddings + "d", Integer.valueOf(String.valueOf(stopWatch.getTotalTimeMillis())));
            performanceRedisTemplate.opsForValue().append(appendingPerformanceKey, timestamp + durationPadded);
        }
    }

    public void setPerformanceRedisTemplate(RedisTemplate<RedisKey, String> performanceRedisTemplate) {
        this.performanceRedisTemplate = performanceRedisTemplate;
    }

    public void setRedisConfigManager(RedisConfigManager redisConfigManager) {
        this.redisConfigManager = redisConfigManager;
    }

    public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
        this.securityContextHolderStrategy = securityContextHolderStrategy;
    }

    public void setApplication(String application) {
        this.application = application;
    }
}
